Putting stuff in the border
By Richard Bennett
Copyright (c) 1991 Apple Users' Group, Sydney
Republished from Applecations, a publication of the Apple Users' Group, Sydney, Australia.
Since I wrote the program ILTS, in 1988, various people have asked after the display technique I'd used. But alas, I was just beaten to publication, two years later, by David Kopper in the October 1990 issue of 8/16. It seems however that Mr. Kopper is a little ill-informed in regard to technique, as his article, titled "Overscan", simply missed the point. It is obvious that the technique of "putting stuff in the border" (I've never heard the term "overscan" before) is still misunderstood by most, and is actually part of a more general technique called "watching the VBL counters alot". It has also since been described in IIgs Tech Note #39, and a follow up article in 8/16 describing how to put simple scrolling text in the border.
When I saw the first FTA demo, I also asked myself "How?". So I dug out my beta Firmware Reference and checked all the locations in the hardware page. Sure enough, I found the answer in the form of the locations $E0/C02E (VERTCNT) and $E0/C02F (HORIZCNT). By polling these locations for the current address of the electron beam, you could theoretically change anything you wished, at any location on the screen, at any time during the screen re-trace.
As you can see from Tech Note #39, VERTCNT supplies bit1 through bit8 of the current line address, and HORIZCNT bit0 supplies bit0. Together, these nine bits describe the current line address. However if you read from just VERTCNT, the value ranges from $7D to $FF, with each increment representing two scan lines, and the value $80 representing the top line of the screen. Thus with one location read, you are able to get accuracy down to two scan lines, which on the text screen is more than enough, considering that each character is eight lines high.
My first attempt, was in the ILTS program. ILTS is used to save your battery RAM parameters to the boot blocks of any disk, which can then be restored whenever you wish. However at that stage, I was going to use super hi-res to get multiple coloured text on the screen. If you launch ILTS, you will see that not only is there different coloured text, but also 40 columns and 80 columns, and different colours in the border. The program sets the border, text and background colours to black, draws the text on the screen, and then enters the following loop to display the screen:
KEY LDX #0*4+$80+1 ;Wait for scan line 1 to start (top is line 0)
CPX $C02E
BNE *-3
LDY #2 ;Delay for accelerators
DEY
BNE *-1
LDA #$8 ;Brown background, black (no) text
STA $C022
LDA #$48 ;Brown border- Line across entire screen
STA $C034
LDX #1*4+$80-2 ;Wait for scan line 4 to start
CPX $C02E
BNE *-3
LDY #2
DEY
BNE *-1
LDA #$D0 ;Yellow text, black background- Normal screen
STA $C022
LDA #$40 ;Black border- Nothing in the border area
STA $C034
LDX #3*4+$80+2 ;Wait for scan line 28 to start
CPX $C02E
BNE *-3
LDY #2
DEY
BNE *-1
LDA #$8 ;Brown background, black (no) text
STA $C022
LDA #$48 ;Brown border- The line is drawn yet again
STA $C034
LDX #4*4+$80-1 ;Wait for scan line 30 to start
CPX $C02E ; which is just before text line 4
BNE *-3
LDY #2
DEY
BNE *-1
LDA #$10 ;Red text, black background
STA $C022
LDA #$40 ;Black (no) border- Back to normal red text
STA $C034
LDX #20*4+$80+1 ;Wait for scan line 162 to start
CPX $C02E ; which is just after text line 20
BNE *-3
LDY #2
DEY
BNE *-1
LDA #$8 ;Brown background, black (no) text
STA $C022
LDA #$48 ;Brown border- Drawing the line again!
STA $C034
LDX #21*4+$80-2 ;Wait for scan line 164 to start
CPX $C02E
BNE *-3
LDY #2
DEY
BNE *-1
LDA #$30 ;Puple text, black background
STA $C022
LDA #$40 ;Black (no) border- Get ready for 80 cols
STA $C034
STA $C00D ;80 columns on
LDX #23*4+$80 ;Wait for scan line 184 to start
CPX $C02E
BNE *-3
LDA #$40 ;Dark green text, black background
STA $C022
STA $C00C ;40 columns again
LDA $C000 ;Did they press a key on this trace cycle
BPL :GOTIT
JMP KEY
:GOTIT LDX #$10 ;Reset the screen first!
STX $C022 ; to Deep red text, black background,
STA $C010 ;Clear keyboard latch and return with keypress
RTS
As you can see, the processor is permanently busy cycling through the various scan lines. To reflect the counter's change of address immediately, the X-register is loaded with the required scan line number, and a small spin wait is entered until the IIgs video has caught up to the processor. Since the alignment of various monitors can be out slightly, and that the address in VERTCNT is reflected slightly before the beam reaches that actual line, another timer delay of 16 cycles is used, in the form of a decrementing Y-register. Normally this delay is not required, however if you have an accelerator currently active, then the subsequent store instructions may execute before the beam has caught up. Hence the delay is commented in the above source as "Delays for accelerators".
Ok, so you can do neat tricks with the text screen. Now how about graphics?
It is obvious from the above code that if something can be done quickly via a couple of instructions, then it can be used within the loop. As we all know, the following instructions turn on the standard super hi-res mode:
LDAL $E0C029
ORA #%1100_0000
STAL $E0C029
Yes, you can mix super hi-res and text in any combination on the screen. However there are some problems, in regard to the screen addressing and size. Try the following program:
START LDA #$C1 ;First turn on SHR
STA $C029
LDA #$A0 ;Wait for line $A0/2 = $50 = 80
CMP $C02E
BNE *-3
LDA #$41 ;Now switch to text mode (SHR off)
STA $C029
LDA #$C0
CMP $C02E ;Wait for line $C0/2 = $60 = 96
BNE *-3
BRA START ;Loop back and turn SHR on
As you can see, there is a three to four text line display change time. So mixed text and graphics start to place restrictions on our displays. However if you are using graphics anyway, why bother using the text screen right?!
With graphics, lines can be triggered using the scan line interrupt of the hardware, which pretty much negates the necessity for VERTCNT monitoring code. However from a coding time point of view, VERTCNT could be a solution.
In a GS/OS application, when interrupts are being flung around the system at a great rate, however invisible they appear, or don't appear, to the user, the VERTCNT monitoring code needs a few modifications. In the time it takes for the beam to pass two complete scan lines, which in our previous examples is only a one value change in VERTCNT, the processor only gets to execute a limited number of cycles. If you take the 127usec period mentioned in the Tech Note, and the processor running at an effective system speed of 2.6Mhz, theorectically you should get around 330 clock cycles between each VERTCNT value change. My timing tests could only get about 227 cycles however, and I couldn't find any other reference to the change delay in any of the other manuals, except the 127usec quoted in the Tech Note. However a 227 to 330 cycle window could become restrictive when you start to consider interrupt overheads. So, your VERTCNT monitoring code should disable interrupts while active.
START PHP ;Save current interrupt flag
SEI ;Disable them
LDA #$A0 ;Do our VERTCNT stuff
CMPL $E0C02E ;(GS/OS application, don't assume I/O shadowing)
BCC *-3
PLP ;Restore original interrupt flag
The only problem here, is that interrupts could be disabled for a maximum of one complete screen re-trace, which at 60 Hertz is a sixtieth of a second. (However as long as you don't mention it to Apple Tech Support, you shouldn't have a problem!)
I've purposely only covered the basics of "overscan", for with this knowledge you should be able to work out how all of the FTA demonstrations were coded, as well as having a few more "tricks" in your programming kitbag. I'd also like to apologise to MG for taking so long to get an article written. But then again, 30 months isn't really that long is it?
Permission is hereby granted for non-profit user groups to republish this content. PLEASE CREDIT THE AUTHOR AND THE SOURCE: Applecations, publication of the Apple Users' Group, Sydney, Australia